﻿#include "RemoteFileDialog.h"



//请求远程对方文件返回列表：
#define REQUEST_FILE_LIST "request_file_list"
//响应远程对方文件返回列表：
#define RESPONSE_FILE_LIST "respnose_file_list"


//用来识别文件类型的函数：
QString FileTypereturn(const QFileInfo& info);


RemoteFileDialog::RemoteFileDialog(QWidget* parent)
	:QWidget(parent)
	, ui(new Ui::Form)
{
	ui->setupUi(this);

	//allinit:
	init();
}
RemoteFileDialog::~RemoteFileDialog()
{
	m_websockclient->close();
	delete m_websockclient;



	delete ui;
}

void RemoteFileDialog::init()
{
	//布局初始化：
	layoutinit();

	//web连接：
	start(QUrl("ws://127.0.0.1:8888"));
}







void RemoteFileDialog::layoutinit()
{
	this->setWindowIcon(QIcon("./images/client.ico"));
#if 0
	//去掉边框和状态栏：
	this->setWindowFlag(Qt::FramelessWindowHint);
	//去掉后，窗口就不能正常移动了，所以最方便的方法就是手动添加个类来调用实现：
	QObject::installEventFilter(new eventFilterObject(this));
#endif



	//1.本地设备：
	localinit();
	

	//2.远程设备：
	remoteinit();


	detailinit();


	//3.传输按钮：
	QObject::connect(ui->transmitBtn, &QPushButton::clicked, this, &RemoteFileDialog::transmit);
	//QObject::connect(ui->transmitBtn, &QPushButton::clicked, this, &RemoteFileDialog::UpdateDetailView);

	//传输数据更新，信号槽连接：
	QObject::connect(this, &RemoteFileDialog::transmitdata, this, &RemoteFileDialog::UpdateDetailView);


	//3.2本地和远程目录视图互斥，只能有一个视图中的文件项被选择：
	QObject::connect(ui->localView, &QTableView::clicked, this, [=]
		{
			ui->remoteView->setCurrentIndex(QModelIndex());			//设置当前下标为非法
		});
	QObject::connect(ui->remoteView, &QTableView::clicked, this, [=]
		{
			ui->localView->setCurrentIndex(QModelIndex());			//设置当前下标为非法
		});


	//4.右键菜单：
		//4.1菜单配置;
	m_contextmenu = new QMenu(this);
			//4.1.0.打开功能项：
	m_contextmenu->addAction("在文件资源管理器中打开", this, [=]
		{
			if (m_menutype == localmenu)
			{
				auto index = ui->localView->currentIndex();
				auto filename = m_localFileModel->data(m_localFileModel->index(index.row(), 0), Qt::DisplayRole).toString();
				QDesktopServices::openUrl(QUrl::fromLocalFile(m_localFileDir.canonicalPath() + "/" + filename));
			}
			else
			{
				QMessageBox::about(0, QObject::tr("hint~"), "该路径是远程设备，不能异地打开该文件资源管理器~");
			}
			
		});
			//4.1.1传输功能项：
	m_contextmenu->addAction("传输",this,&RemoteFileDialog::transmit);
			//4.1.2.复制功能项：
	m_contextmenu->addAction("复制", this, [=]
		{
			if (m_menutype = localmenu)			//在本地文件中复制
			{
				auto index = ui->localView->currentIndex();
				auto filename = m_localFileModel->data(m_localFileModel->index(index.row(), 0),Qt::DisplayRole).toString();
				//保存文件的文件名+文件路径：
				m_optionfile = m_localFileDir.canonicalPath() + "/" + filename;
				qDebug() << "local copy successful" << m_optionfile;
			}
			else                                //在远程文件中复制
			{
				auto index = ui->remoteView->currentIndex();
				auto filename = m_remoteFileModel->data(m_remoteFileModel->index(index.row(), 0),Qt::DisplayRole).toString();
				//保存文件的文件名+文件路径：
				m_optionfile = m_remoteFileDir.canonicalPath() + "/" + filename;
				qDebug() << "local copy successful" << m_optionfile;
			}
			//保存文件复制的来源类型：
			m_optionype = m_menutype;
			qDebug() << m_optionype;
		});
			//4.1.3.粘贴功能项：
	//粘贴功能是只针对于本地文件到远程文件目录中的粘贴的（在当前窗口复制过后，也不能在其他app中粘贴）：所以要获取当前远程文件的目录；还有在没有复制前，粘贴功能项应是不可选，灰色的；
	auto pasteAct = m_contextmenu->addAction("粘贴", [=]
		{
			SendFile(m_optionfile, m_remoteFileDir.canonicalPath());
		});
	pasteAct->setEnabled(false);				//设置粘贴功能项默认不可选，被禁用
			//4.1.4.删除功能项：
	m_contextmenu->addAction("删除", this, [=]
		{
			QMessageBox::about(0, QObject::tr("hint~"), "确定要删除该文件？");


			//本地文件来源类型的删除：
			if (m_menutype == localmenu)
			{
#if 0
				auto index = ui->localView->currentIndex();
				auto filename = m_localFileModel->data(m_localFileModel->index(index.row(), 0), Qt::DisplayRole).toString();

				//开始删除本地文件，通过文件名和文件路径;
				if (QFile::remove(m_localFileDir.canonicalPath() + "/" + filename))
				{
					qDebug() << filename << "（本地）文件 删除成功";
					m_localFileModel->removeRow(index.row());
					QMessageBox::about(0, QObject::tr("hint~"), "该本地文件删除成功~");
				}
				else
				{
					qWarning() << filename << "（本地）文件 删除失败";
					QMessageBox::about(0, QObject::tr("hint~"), "该本地文件删除失败~");
				}
#endif
				QModelIndexList localrows = ui->localView->selectionModel()->selectedRows();
				if (localrows.isEmpty())
				{
					QMessageBox::about(0, QObject::tr("hint~"), "请先选择文件");
					return;
				}
				for (const auto& v : localrows)
				{
					auto filename = m_localFileModel->data(m_localFileModel->index(v.row(), 0), Qt::DisplayRole).toString();
					
					if (QFile::remove(m_localFileDir.canonicalPath() + "/" + filename))
					{
						qDebug() << filename << "（本地）文件 删除成功";
						m_localFileModel->removeRow(v.row());
					}
					else
					{
						qWarning() << filename << "（本地）文件 删除失败";
						QMessageBox::about(0, QObject::tr("hint~"), "该本地文件删除失败~");
					}
				}
				QMessageBox::about(0, QObject::tr("hint~"), "该本地文件删除成功~");
			}
			//远程文件来源类型的删除：
			else
			{
#if 0
				auto index = ui->remoteView->currentIndex();
				auto filename = m_remoteFileModel->data(m_remoteFileModel->index(index.row(), 0), Qt::DisplayRole).toString();

				//发送给远程设备，需要远程设备自己去删除，本地不可实现删除远程文件：
				SendJson(
					{
						{"type","request_deletefile"},
						{"filenamepath",m_remoteFileDir.canonicalPath() + "/" + filename}
					}
				);
#endif
				QModelIndexList remoterows = ui->remoteView->selectionModel()->selectedRows();
				if (remoterows.isEmpty())
				{
					QMessageBox::about(0, QObject::tr("hint~"), "请先选择文件");
					return;
				}
				for (const auto& v : remoterows)
				{
					auto filename = m_remoteFileModel->data(m_remoteFileModel->index(v.row(), 0), Qt::DisplayRole).toString();
					//发送给远程设备，需要远程设备自己去删除，本地不可实现删除远程文件：
					SendJson(
						{
							{"type","request_deletefile"},
							{"filenamepath",m_remoteFileDir.canonicalPath() + "/" + filename}
						}
					);
				}
			}
		});
			//4.1.5.重命名功能项：
	m_contextmenu->addAction("重命名", this, [=]
		{
			//本地文件：
			if (m_menutype == localmenu)
			{
				auto index = ui->localView->currentIndex();
				auto filename = m_localFileModel->data(m_localFileModel->index(index.row(), 0), Qt::DisplayRole).toString();
				ui->localView->edit(index);
				connect(m_localFileModel, &QStandardItemModel::itemChanged, [=](QStandardItem* item)
				{
					qDebug() << "重命名成功";
					m_localFileDir.rename(filename, item->text());
				});
			}
			//远程文件：
			else
			{
				auto index = ui->remoteView->currentIndex();
				auto filename = m_remoteFileModel->data(m_remoteFileModel->index(index.row(), 0), Qt::DisplayRole).toString();
				ui->remoteView->edit(index);
				connect(m_remoteFileModel, &QStandardItemModel::itemChanged, [=](QStandardItem* item)
				{
					SendJson(
						{
									{"type","request_rename"},
									{"path",m_remoteFileDir.canonicalPath()},
									{"oldname",filename},
									{"newname",item->text()}
						}
					);
					
				});
			}
		});
			//4.1.6.新建文件夹功能项：
	m_contextmenu->addAction("新建文件夹", this, [=]
		{
			//如果是本地文件：
			if (m_menutype == localmenu)
			{
				//1.创建文件夹：
				QString folder = "新建文件夹";
				if (!m_localFileDir.mkdir(folder))
				{
					qDebug() << "创建文件夹失败";
				}
				//UpdateLocalFile();


				//2.给TableView视图添加项：
				QList<QStandardItem* > items;
				auto item = new QStandardItem(folder);
				item->setIcon(m_fileIconprovider.icon(QFileIconProvider::IconType::Folder));			//设置当前文件名的图标
				items.append(item);							//加入该文件的文件名附带文件图标
				items.append(new QStandardItem());			//加入该文件的文件大小
				items.append(new QStandardItem());			//加入该文件的最后修改日期
				items.append(new QStandardItem("文件夹"));	//加入该文件的文件类型
				//插入数据信息：
				m_localFileModel->appendRow(items);


				//3.TableView视图	跳转到最下面，因为没有更新视图，所以新创建的文件夹默认是在该视图的最后的，所以要跳转到最下面，方便修改文件名：
				ui->localView->scrollToBottom();
				//4.TableView视图的编辑，编辑的下标是item的下标；（只要添加项成功了，就会有返回下标的值）
				ui->localView->edit(item->index());
				//新创建的文件夹也是默认不能有重名的；
			}
			//如果是远程文件：
			else
			{
				//不能像本地设备那样新建操作，因为这是远程设备，要发送创建文件夹的指令：
				SendJson(
					{
							{"type","request_mkdir"},
							{"newfilename","新建文件夹"},
							{"path",m_remoteFileDir.canonicalPath()}
					});


				QObject::connect(m_remoteFileModel, &QStandardItemModel::itemChanged, [=](QStandardItem* item)
				{
					//不能像本地设备那样新建操作，因为这是远程设备，当前远程设备的视图模型的项改变了（增加了），就表示远程设备创建了新的文件夹，更新后的目录数据已发送到本地；
					//然后要改名，把	以前的名字	和	新的名字	以及		当前的文件路径		都发送给远程设备，让远程设备去改名：
					SendJson(
						{
								{"type","request_rename"},
								{"oldname",item->data(Qt::UserRole).toString()},
								{"newname",item->text()},
								{"path",m_remoteFileDir.canonicalPath()}
						}
					);
				});

			}
		});
			//4.1.7.全选功能项：
	m_contextmenu->addAction("全选", this, [=]
		{
			//如果是本地文件：
			if (m_menutype == localmenu)
			{
				ui->localView->selectAll();
			}
			//如果是远程文件：
			else
			{
				ui->remoteView->selectAll();
			}
		});


		//4.2.1本地文件连接自定义菜单功能项信号槽：
	QObject::connect(ui->localView, &QTableView::customContextMenuRequested,this, [=](const QPoint& pos)
		{
			qDebug() << "localView	customContextMenuRequested 信号触发";


			//如果上次复制的来源类型也是本地文件，那么粘贴键就不可选中：
			if (m_optionype == localmenu)
			{
				pasteAct->setEnabled(false);
			}
			//如果上次复制的额来源类型不是本地文件，而且该复制文件不为空，则打开粘贴功能项的可用：
			else if(!m_optionfile.isEmpty())
			{
				pasteAct->setEnabled(true);
			}


			m_menutype = localmenu;
			//有两种把窗口坐标变成全局坐标的方法，这是方法1；
			m_contextmenu->popup(ui->localView->mapToGlobal(pos) + QPoint(25, 25));
		});
		//4.2.2远程文件连接自定义菜单功能项信号槽：
	QObject::connect(ui->remoteView, &QTableView::customContextMenuRequested,this, [=](const QPoint& pos)
		{
			qDebug() << "remoteView		customContextMenuRequested 信号触发";


			//如果上次复制的来源类型也是远程文件，那么粘贴键就不可选中，被禁用，反之可用：
			if (m_optionype == remotemenu)
			{
				pasteAct->setEnabled(false);
			}
			//如果上次复制的额来源类型不是远程文件，而且该复制文件不为空，则打开粘贴功能项的可用：
			else if(!m_optionfile.isEmpty())
			{
				pasteAct->setEnabled(true);
			}


			m_menutype = remotemenu;
			//有两种把窗口坐标变成全局坐标的方法，这是方法2：
			m_contextmenu->popup(QCursor::pos());
		});

}







//本地设备：
void RemoteFileDialog::localinit()
{
	//定义模型：
	m_localFileModel = new QStandardItemModel(this);
	ui->localView->setModel(m_localFileModel);

	

	ui->localView->setEditTriggers(QTableView::NoEditTriggers);									//设置不可选取
	ui->localView->setSelectionMode(QTableView::SelectionMode::ContiguousSelection);			//设置选择模式
	ui->localView->setSelectionBehavior(QTableView::SelectionBehavior::SelectRows);				//设置一行选取
	ui->localView->verticalHeader()->setVisible(false);										//设置左边序列号取消显示
	ui->localView->setShowGrid(false);														//设置在QTableView中隐藏列之间的分隔线



	//设置菜单请求信号：		没有这个，信号槽触发不了；
	ui->localView->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);


#if 1
	//把当前主机的桌面路径保存在m_localFileDir里：
	m_localFileDir.setPath(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
#else		//test!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1
	m_localFileDir.setPath("D:\\qt_course_18\\26 文件传输二");
#endif

	//更新TableView视图数据信息：
	UpdateLocalFile();


	//链接信号槽：
	QObject::connect(ui->localFile_backBtn, &QPushButton::clicked, this, &RemoteFileDialog::onLocalFileBack);				//返回上一级按钮
	QObject::connect(ui->localFile_flushBtn, &QPushButton::clicked, this, &RemoteFileDialog::onLocalFileFlush);			//返回刷新按钮
	QObject::connect(ui->localFile_newBtn, &QPushButton::clicked, this, [=]
		{
			//1.创建文件夹：
			QString folder = "新建文件夹";
			if (!m_localFileDir.mkdir(folder))
			{
				qDebug() << "创建文件夹失败";
			}
			//UpdateLocalFile();


			//2.给TableView视图添加项：
			QList<QStandardItem* > items;
			auto item = new QStandardItem(folder);
			item->setIcon(m_fileIconprovider.icon(QFileIconProvider::IconType::Folder));			//设置当前文件名的图标
			items.append(item);							//加入该文件的文件名附带文件图标
			items.append(new QStandardItem());			//加入该文件的文件大小
			items.append(new QStandardItem());			//加入该文件的最后修改日期
			items.append(new QStandardItem("文件夹"));	//加入该文件的文件类型
				//插入数据信息：
			m_localFileModel->appendRow(items);

			
			//3.TableView视图	跳转到最下面，因为没有更新视图，所以新创建的文件夹默认是在该视图的最后的，所以要跳转到最下面，方便修改文件名：
			ui->localView->scrollToBottom();
			//4.TableView视图的编辑，编辑的下标是item的下标；（只要添加项成功了，就会有返回下标的值）
			ui->localView->edit(item->index());
			//新创建的文件夹也是默认不能有重名的；
		});																															//新建文件夹按钮
	QObject::connect(m_localFileModel, &QStandardItemModel::itemChanged, [=](QStandardItem* item)
		{
			m_localFileDir.rename("新建文件夹", item->text());
		});																															//模型里面的项目改变了（项目名改变了），就触发改变文件名
	QObject::connect(ui->localView, &QTableView::doubleClicked, this, &RemoteFileDialog::onLocalTableViewDoubleClicked);	//双击视图
#if 0					//有本地文件重复显示的问题；现用回车键所搜下拉框路径
	connect(ui->localFile_curfilepathCmb, &QComboBox::currentIndexChanged, [=]
		{
			qDebug() << "signal QComboBox::currentIndexChanged ";
			this->setLocalFilePath(ui->localFile_curfilepathCmb->currentText());
		});																															//点击下拉框改变下标索引
#endif
	QObject::connect(ui->localFile_curfilepathCmb->lineEdit(), &QLineEdit::returnPressed, [=]
		{
			this->setLocalFilePath(ui->localFile_curfilepathCmb->currentText());
		});																															//改变下拉框文本，索引路径
}
void RemoteFileDialog::UpdateLocalFile()
{
	//打印当前路径：
	qDebug() <<"local >\t" << m_localFileDir.absolutePath() << "---" << m_localFileDir.path();

	m_localFileModel->clear();
	//寻找当前路径是否在下拉框里存在：
	auto idx = ui->localFile_curfilepathCmb->findText(m_localFileDir.absolutePath());
			//如果存在，就显示它在下拉框上的下标索引，并设置当前索引，显示出它的路径
	if (-1 != idx)
	{
		ui->localFile_curfilepathCmb->setCurrentIndex(idx);
	}
			//如果不存在，就添加它的路径到下拉框中，并设置当前索引：
	else
	{
		ui->localFile_curfilepathCmb->addItem(m_localFileDir.absolutePath());
		ui->localFile_curfilepathCmb->setCurrentIndex(ui->localFile_curfilepathCmb->count() - 1);
		//会触发QComboBox::currentIndexChanged信号，然后在运行槽函数，所以会把路径打印两次
	}
	//下拉框的保存路径不能大于10：
	if (ui->localFile_curfilepathCmb->count() > 10)
	{
		ui->localFile_curfilepathCmb->removeItem(0);
	}

	//设置路径属性是没有"."和".." ，以及所有路径都可以进入：
	QDirIterator iter(m_localFileDir.absolutePath(), QDir::AllEntries | QDir::NoDotAndDotDot);
	while (iter.hasNext())
	{
		auto info = iter.nextFileInfo();
		auto type = FileTypereturn(info);
		//给TableView要插入的数据信息进行加载：
		QList<QStandardItem* > items;
		auto item = new QStandardItem(info.fileName());
		item->setIcon(m_fileIconprovider.icon(info));						//设置当前文件名的图标，根据它的索引和类实现；
		items.append(item);														//加入该文件的文件名附带文件图标
		items.append(new QStandardItem(type == "文件夹" ? "" : FitByteDisplayText(info.size())	/*传入字节大小，返回适合现实的文本*/));			//加入该文件的大小，如果是文件夹就不需要大小了
		items.append(new QStandardItem(info.fileTime(QFile::FileTime::FileModificationTime).toString("yyyy/MM/dd hh:mm")));	//加入该文件的最后修改日期
		items.append(new QStandardItem(FileTypereturn(info)));					//加入该文件的文件类型，由自定义静态内部函数，在内部函数中，由QFIleInfo类的成员函数的返回值来判定
		//插入数据信息：
		m_localFileModel->appendRow(items);

		/*
		注意：以下是对QTableView的视图水平表头和各列大小的的调整：
		*/
		// 获取水平表头
		QHeaderView* header = ui->localView->horizontalHeader();
		SetViewHorizontalHead(header,m_localFileModel,ui->localView);
	}
}
void RemoteFileDialog::setLocalFilePath(const QString& path)
{
	m_localFileDir.setPath(path);
	UpdateLocalFile();
}
void RemoteFileDialog::onLocalFileBack()
{
	qDebug() << "onLocalFileBack clicked\n";
	m_localFileDir.cdUp();
	UpdateLocalFile();
}
void RemoteFileDialog::onLocalFileFlush()
{
	qDebug() << "onLocalFileFulsh clicked\n";
	UpdateLocalFile();
}
void RemoteFileDialog::onLocalTableViewDoubleClicked(const QModelIndex& index)
{
	//搞出当前双击下标索引的文件的文件名：
	auto filename = m_localFileModel->data(m_localFileModel->index(index.row(), 0)).toString();
	qDebug() << "doubleclicked filename is > " << filename;

	//合并文件名路径：
	QFileInfo info (m_localFileDir.absolutePath() + "/" + filename);
	if (info.isDir())			//如果是个文件夹，就进入，并且更新模型视图
	{
		m_localFileDir.cd(filename);
		UpdateLocalFile();
	}
}







//web客户端配置函数：
void RemoteFileDialog::start(const QUrl& url)
{
	if (!m_websockclient)
	{
		m_websockclient = new QWebSocket("Remote_file_transfer");

		//设置websocket暂停状态：
		m_websockclient->setPauseMode(QAbstractSocket::PauseOnSslErrors);


		//信号槽连接
		QObject::connect(m_websockclient, &QWebSocket::errorOccurred, this, [=]
			{
				qDebug() << url.toString() << "web 连接失败\n";
			});
		QObject::connect(m_websockclient, &QWebSocket::connected, this, &RemoteFileDialog::onConnected);
		QObject::connect(m_websockclient, &QWebSocket::disconnected, this, &RemoteFileDialog::onDisConnected);
		QObject::connect(m_websockclient, &QWebSocket::binaryMessageReceived, this, &RemoteFileDialog::onBinaryMessageReceived);
		QObject::connect(m_websockclient, &QWebSocket::textMessageReceived, this, &RemoteFileDialog::onTextMessageReceived);
		QObject::connect(m_websockclient, &QWebSocket::stateChanged, this, &RemoteFileDialog::onSocketstateChanged);
	}
	//这个东西一定不要忘，忘写了就不会连接:
	m_websockclient->open(url);
}
//新的连接槽函数：
void RemoteFileDialog::onConnected()
{
	qDebug() << "onConnected    新的连接槽函数触发>>>>";

	GetRemoteFile();

}
//断开连接槽函数
void RemoteFileDialog::onDisConnected()
{
	qDebug() << "onDisConnected    断开连接槽函数触发>>>>";
}
//二进制格式消息数据接收槽函数：
void RemoteFileDialog::onBinaryMessageReceived(const QByteArray& data)
{
	//qDebug() << "onBinaryMessageReceived    二进制格式消息数据接收槽函数触发>>>>";


	//本地接受远程设备发来的文件数据并写入文件数据：
	if (m_recvfile)
	{
		m_recvfile->write(data);


		//显示传输速度：
		QString data = m_recvfile->fileName()/*名称*/ + "\tIn transmission\t"/*状态*/ + FitByteDisplayText(m_recvfile->size())/*已传输大小*/ +"\t"
			+ FitByteDisplayText(m_totalfilesize)/*总传输大小*/ + "\t" + TransmissionSpeed(m_recvfile->size(), m_elapsedtimier.elapsed())/*传输速度*/ + "\t" 
			+ TransmitRemainingTime(m_recvfile->size(), m_totalfilesize, m_elapsedtimier.elapsed())/*剩余时间*/;
		qDebug() << data;

		//QStandardItem* item = new QStandardItem(data);
		//m_detailModel->appendRow(item);

		//发送信号，把传输信息传递给信号：
		emit transmitdata(data);


		//如果接收到文件的数据的大小和发来的总的文件大小相同，那就传输完毕了：
		if (m_recvfile->size() == m_totalfilesize)
		{
			qDebug() << m_recvfile->fileName() << "该接收文件完成~~~";

			//发送信号，把传输信息完成的信息传递给信号：
			emit transmitdata(m_recvfile->fileName() + "\t" + "该接收文件完成~~~");


			//关闭释放：
			m_recvfile->close();
			m_recvfile->deleteLater();
			m_recvfile = nullptr;
			m_totalfilesize = 0;

			QMessageBox::about(0, QObject::tr("finish~"), "文件传输完成，记得刷新远程文件哦~");
		}
	}
}
//文本格式数据消息接受槽函数：
void RemoteFileDialog::onTextMessageReceived(const QString& data)
{
	//qDebug() << "onTextMessageReceived    文本格式数据消息接受槽函数触发>>>>";


	QJsonParseError error;					//创建一个空的QJsonParseError对象，用于判断是否产生错误
	auto jdocument = QJsonDocument::fromJson(data.toUtf8(), &error);
	if (error.error != QJsonParseError::NoError)		//如果不和QJsonParseError的枚举值NoError相等，就是有错误
	{
		qWarning() << "json parse error  >  " << error.errorString();
		return;
	}


	//获取消息类型：
	auto jtype = jdocument["type"].toString();
	//qDebug() << "jdocument type >> " << jtype;




	if (jtype == REQUEST_FILE_LIST)                  //如果收到的类型是	请求远程对方文件返回列表	是用于发送数据
	{
		auto path = jdocument["path"].toString();


#if 1
		path = (path.isEmpty() ? QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) : path);//如果参数的路径是空的，那就把本主机的桌面路径发送过去
#else		//test!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		path = (path.isEmpty() ? "D:\\vs-code\\Qt_project\\Remote_file_transfer\\test" : path);//如果参数的路径是空的，那就把本主机的桌面路径发送过去
#endif


		SendJson(GetAllFiles(path));
	}
	else if (jtype == RESPONSE_FILE_LIST)			//如果收到的类型是		响应远程对方文件返回列表	是用于接收数据
	{
		UpdateRemoteFile(jdocument.object());
	}
	else if (jtype == "send")						//如果收到的类型是		"send"					表示有远程设备给本地发送文件了，本地要接受文件信息；
	{
		//通过data里面的键"filename"来获取对应的值，所谓文件名：
		m_filename = jdocument["filename"].toString();
		//通过data里面的键"filesize"来获取对应的值，所谓文件大小：
		m_totalfilesize = jdocument["filesize"].toInteger();
		//通过data里面的键"filepath"来获取对应的值，所谓文件路径：
		auto filepath = jdocument["filepath"].toString();

		//判断当前的路径是否存在，如果不存在，就创建当前路径，这是针对于文件夹来实行的操作：
		QDir dir(filepath);
		if (!dir.exists())
		{
			if (!dir.mkpath(filepath))
			{
				qWarning() << filepath << "创建路径失败";
				return;
			}
		}


		m_recvfile = new QFile(filepath + "/" + m_filename);
		if (!m_recvfile->open(QIODevice::WriteOnly | QIODevice::Append))
		{
			qDebug() << m_recvfile->fileName() << "打开失败" << m_recvfile->errorString();
			QMessageBox::about(0, QObject::tr("hint~"), "文件传输失败，或是传输路径出现问题");
		}
		else
		{
			m_elapsedtimier.restart();
		}
	}
	else if (jtype == "receive")					//如果收到的类型是		"receive"				表示有远程设备给本地发送文件了，本地要接受文件信息；
	{
		auto peerfilepath = jdocument["filepath"].toString();
		auto jarray = jdocument["send_file_list"].toArray();
		for (int i = 0; i < jarray.size(); i++)
		{
			auto filename = jarray.at(i).toString();
			SendFile_or_Folder(filename, peerfilepath);
		}
	}
	else if (jtype == "stop")
	{
		m_recvfile->open(QIODevice::NotOpen);
	}
	else if (jtype == "request_mkdir")				//如果收到的类型是		"request_mkdir"			表示有远程设备请求本地创建新的文件夹；
	{
		//进入文件目录：
		QDir dir(jdocument["path"].toString());
		//在当前选择的目录下创建文件夹：
		dir.mkdir(jdocument["newfilename"].toString());
		//这样就文件创建完成了，我们需要给远程文件发送Json来告诉他文件已经创建完成了，现在可以执行修改文件夹的名字的步骤了;


		//给远程设备发送回复数据，让远程设备定义出新的文件名：
		SendJson(
			{
					{"type","respnose_mkdir"},
					{"newfilename",jdocument["newfilename"].toString()}
			}
		);
	}
	else if (jtype == "respnose_mkdir")				//如果收到的类型是		"respnose_mkdir"		表示远程设备已经创建完新文件夹，要求本地设置新的文件夹名称；
	{
		//把新的文件夹添加项	到远程文件目录视图中;
		QList<QStandardItem* > items;
		auto item = new QStandardItem(jdocument["newfilename"].toString());
		item->setIcon(m_fileIconprovider.icon(QFileIconProvider::IconType::Folder));			//设置当前文件名的图标
		item->setData(jdocument["newfilename"].toString(), Qt::UserRole);		//将新的文件夹的原来名成数据		存储在列表项的UserRole属性中，以便用旧名称设置新名称
		items.append(item);											//加入该文件的文件名附带文件图标
		items.append(new QStandardItem());							//加入该文件的文件大小
		items.append(new QStandardItem());							//加入该文件的最后修改日期
		items.append(new QStandardItem("文件夹"));					//加入该文件的文件类型
		//插入数据信息：
		m_remoteFileModel->appendRow(items);


		//TableView视图	跳转到最下面，因为没有更新视图，所以新创建的文件夹默认是在该视图的最后的，所以要跳转到最下面，方便修改文件名：
		ui->remoteView->scrollToBottom();
		//TableView视图的编辑，编辑的下标是item的下标；（只要添加项成功了，就会有返回下标的值）
		ui->remoteView->edit(item->index());
		//新创建的文件夹也是默认不能有重名的；
	}
	else if (jtype == "request_rename")				//如果收到的类型是		"request_rename"		表示远程设备已经设置完新的文件夹名称，要求本地使用函数去重命名；
	{
		//进入文件目录;
		QDir dir(jdocument["path"].toString());
		//文件重命名：
		dir.rename(jdocument["oldname"].toString(), jdocument["newname"].toString());
	}
	else if (jtype == "request_deletefile")			//如果收到的类型是		"request_deletefile"	表示远程设备请求本地删除指定的文件，删除操作执行过后，给远程设备发送返回删除结果；
	{
		//如果删除文件成功，给远程设备发送	success	信息：
		if (QFile::remove(jdocument["filenamepath"].toString()))
		{
			qDebug() << jdocument["filenamepath"].toString() << "该远程文件删除成功";
			SendJson(
				{
					{"type","response_delete"},
					{"message","success"}
				}
			);
		}
		//如果删除文件失败，给远程设备发送	failed	信息：
		else
		{
			qDebug() << jdocument["filenamepath"].toString() << "该远程文件删除失败";
			SendJson(
				{
					{"type","response_delete"},
					{"message","failed"}
				}
			);
		}
	}
	else if (jtype == "response_delete")			//如果收到的类型是		"response_delete"		表示远程设备已执行完删除操作，接下来要更新本设备对远程文件的文件信息视图显示：
	{
		if (jdocument["message"].toString() == "success")
		{
			auto index = ui->remoteView->currentIndex();
			m_remoteFileModel->removeRow(index.row());
			qDebug() << "远程文件删除操作finish";
			QMessageBox::about(0, QObject::tr("hint~"), "该远程文件删除成功~");
		}
		else
		{
			qDebug() << "远程文件删除操作have error";
			QMessageBox::about(0, QObject::tr("hint~"), "该远程文件删除失败~");
		}
	}

}
void RemoteFileDialog::onSocketstateChanged(QAbstractSocket::SocketState state)
{
	if (state == QAbstractSocket::ConnectedState)
	{
		qDebug() << "Connect to server,network is good";
	}
	else if (state == QAbstractSocket::UnconnectedState)
	{
		qDebug()<< "Connect to server,network is not good";

		QMessageBox::about(0, QObject::tr("error~"), "已和服务器断开连接");
	}
}
//文件传输槽函数：
void RemoteFileDialog::transmit()
{
	QModelIndexList localrows =  ui->localView->selectionModel()->selectedRows();
	QModelIndexList remoterows = ui->remoteView->selectionModel()->selectedRows();
	



	//本地设备传给远程设备：
	if (!localrows.isEmpty())
	{
		for (const auto& index : localrows)
		{
			//获取选中的文件行的文件名：
			auto filename = index.data(Qt::DisplayRole).toString();
			SendFile_or_Folder(m_localFileDir.canonicalPath() + "/" + filename,m_remoteFileDir.canonicalPath());
		}
	}
	//远程设备传给本地设备：
	else if (!remoterows.isEmpty())
	{
		//1.先把要传输的文件列表发给远程设备：
		QJsonArray jarray;
		for (const auto& idx : remoterows)
		{
			auto filenamepath = m_remoteFileDir.canonicalPath() + "/" + idx.data(Qt::DisplayRole).toString();
			jarray.append(filenamepath);
		}
		SendJson(
			{
						{"type","receive"},
						{"filepath",m_localFileDir.canonicalPath()},
						{"send_file_list",jarray}
			});
	}
	//没有选择文件：
	else
	{
		QMessageBox::about(0, QObject::tr("错误~"),"请先选择文件~");
	}
}







void RemoteFileDialog::SendFile_or_Folder(const QString& sourcepath, const QString& peersavepath)
{
	QFileInfo info(sourcepath);
	//文件类型如果是文件：
	if (info.isFile())
	{
		SendFile(info.absoluteFilePath(), peersavepath);
	}
	//文件类型如果是文件夹：
	else if (info.isDir())
	{
		SendFolder(info.absoluteFilePath(), peersavepath);
	}
}
void RemoteFileDialog::SendFile(const QString& filenamepath, const QString& peersavepath)
{
	QFileInfo info(filenamepath);
	//如果是文件，才能发送：
	if (info.isFile())
	{
		//1.发送文件信息
		SendJson(
			{
						{"type","send"},
						{"filename",info.fileName()},
						{"filesize",info.size()},
						{"filepath",peersavepath}
			}
		);


		//2.发送文件数据
			//2.1//获取当前文件名的文件路径
		QFile file(info.absoluteFilePath());
		//如果文件只读模式打开失败，那就返回吧；
		if (!file.open(QIODevice::ReadOnly))
		{
			qDebug() << file.fileName() << "打开失败" << file.errorString();
		}
		//文件可以打开，就发送数据，注意要以二进制的方式发送数据：
		else
		{
			//设定文件大小如果超过4MB，就是大文件，大文件就实行分块发送：
			if (file.size() > 4MB)
			{

				while (!file.atEnd())
				{

					m_websockclient->sendBinaryMessage(file.read(4MB));
				
				}
			}
			// 文件大小不超过4MB，就是小文件，小文件就全部发送：
			else
			{
				m_websockclient->sendBinaryMessage(file.readAll());
			}


			file.close();
		}
	}
}
void RemoteFileDialog::SendFolder(const QString& folderpatth, const QString& peersavepath)
{
	QFileInfo info(folderpatth);
	if (!info.exists() || !info.isDir())
	{
		return;
	}

	QDirIterator iter(folderpatth, QDir::NoDotAndDotDot | QDir::AllEntries, QDirIterator::Subdirectories	/*递归；遍历时也包括子目录*/);


	while (iter.hasNext())
	{
		auto nextinfo = iter.nextFileInfo();

		if (nextinfo.isFile())
		{
			qDebug() << peersavepath + "/" + nextinfo.canonicalPath().remove(info.canonicalPath()).remove(0, 1) + "/" + nextinfo.fileName();


			SendFile(nextinfo.canonicalFilePath(), peersavepath + "/" + nextinfo.canonicalPath().remove(info.canonicalPath()).remove(0, 1));
		}
	}

}







void RemoteFileDialog::SetViewHorizontalHead(QHeaderView* header, QStandardItemModel* m_model, QTableView* ui)
{
	//设置列的调整模式为ResizeToContents	列的大小会根据列中的内容自动调整
	ui->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);


	//使用setStyleSheet函数设置了样式表，将水平表头的各列标题的文本的背景颜色设置为黑色。通过这种方式，你可以修改水平表头的各列标题的文本的背景颜色：
	header->setStyleSheet("QHeaderView::section { background-color: black; }");


	//如果是本地设备模型和远程设备模型：
	if (m_model != m_detailModel)
	{

		//设置水平表头的四个标题内容：
		auto item = new QStandardItem("文件名称");
		item->setForeground(QBrush(QColor(Qt::white)));
		m_model->setHorizontalHeaderItem(0, item);
		item = new QStandardItem("文件名称");
		item->setForeground(QBrush(QColor(Qt::white)));
		m_model->setHorizontalHeaderItem(1, item);
		item = new QStandardItem("修改时间");
		item->setForeground(QBrush(QColor(Qt::white)));
		m_model->setHorizontalHeaderItem(2, item);
		item = new QStandardItem("类型");
		item->setForeground(QBrush(QColor(Qt::white)));
		m_model->setHorizontalHeaderItem(3, item);
	}
	//如果是传输细节模型：
	else
	{
		auto item = new QStandardItem("接收路径\t名称\t状态\t已传输大小\t总传输大小\t速度\t剩余时间");
		item->setForeground(QBrush(QColor(Qt::white)));
		m_model->setHorizontalHeaderItem(0, item);
	}
	

	return;
}







//远程设备：
void RemoteFileDialog::remoteinit()
{
	//首先设置远程文件路径为null；以便排查错误：
	m_remoteFileDir.setPath("");


	//定义模型：
	m_remoteFileModel = new QStandardItemModel(this);
	ui->remoteView->setModel(m_remoteFileModel);
	ui->remoteView->setEditTriggers(QTableView::NoEditTriggers);									//设置不可选取
	ui->remoteView->setSelectionMode(QTableView::SelectionMode::ContiguousSelection);				//设置选择模式
	ui->remoteView->setSelectionBehavior(QTableView::SelectionBehavior::SelectRows);				//设置一行选取
	ui->remoteView->verticalHeader()->setVisible(false);											//设置左边序列号取消显示
	ui->remoteView->setShowGrid(false);														//设置在QTableView中隐藏列之间的分隔线


	//设置菜单请求信号：		没有这个，信号槽触发不了；
	ui->remoteView->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);


	//链接信号槽：
	QObject::connect(ui->remoteFile_backBtn, &QPushButton::clicked, this, &RemoteFileDialog::onRemoteFileBack);				//返回上一级按钮
	QObject::connect(ui->remoteFile_flushBtn, &QPushButton::clicked, this, &RemoteFileDialog::onRemoteFileFlush);				//返回刷新按钮
	QObject::connect(ui->remoteFile_newBtn, &QPushButton::clicked, this, [=]
		{
			//不能像本地设备那样新建操作，因为这是远程设备，要发送创建文件夹的指令：
			SendJson(
				{
						{"type","request_mkdir"},
						{"newfilename","新建文件夹"},
						{"path",m_remoteFileDir.canonicalPath()}
				}
			);
		});																																//新建文件夹按钮
	QObject::connect(m_remoteFileModel, &QStandardItemModel::itemChanged, [=](QStandardItem* item)
		{
			//不能像本地设备那样新建操作，因为这是远程设备，当前远程设备的视图模型的项改变了（增加了），就表示远程设备创建了新的文件夹，更新后的目录数据已发送到本地；
			//然后要改名，把	以前的名字	和	新的名字	以及		当前的文件路径		都发送给远程设备，让远程设备去改名：
			SendJson(
				{
						{"type","request_rename"},
						{"oldname",item->data(Qt::UserRole).toString()},
						{"newname",item->text()},
						{"path",m_remoteFileDir.canonicalPath()}
				}
			);
		});																																//模型里面的项目改变了（项目名改变了），就触发改变文件名
	QObject::connect(ui->remoteView, &QTableView::doubleClicked, this, &RemoteFileDialog::onRemoteTableViewDoubleClicked);		//双击视图
	QObject::connect(ui->remoteFile_curfilepathCmb, &QComboBox::currentIndexChanged, [=]
		{
			qDebug() << "signal QComboBox::currentIndexChanged ";
			m_remoteFileDir.setPath(ui->remoteFile_curfilepathCmb->currentText());
			GetRemoteFile();
		});																																//点击下拉框改变下标索引
	QObject::connect(ui->remoteFile_curfilepathCmb->lineEdit(), &QLineEdit::returnPressed, [=]
		{
			m_remoteFileDir.setPath(ui->remoteFile_curfilepathCmb->currentText());
			GetRemoteFile();
		});																																//改变下拉框文本，索引路径

}
//用于发送数据
QJsonObject RemoteFileDialog::GetAllFiles(const QString& path)
{
	QJsonArray fileArray;			//创建一个空的JSON数组，用于存储文件信息

	//遍历指定路径下的所有文件和目录:
	QDirIterator iter(path, QDir::AllEntries | QDir::NoDotAndDotDot);
	while (iter.hasNext())
	{
		//获取文件信息:
		auto info = iter.nextFileInfo();

		//创建一个新的JSON对象来存储文件信息:
		QJsonObject qobject;	//和花括号外面的变量名相同，但是作用域不同，所以不用担心
				//1.插入文件名、文件大小、文件最后修改时间、文件类型：
		qobject.insert("filename", info.fileName());
		qobject.insert("filesize", info.size());
		qobject.insert("filetime", info.lastModified().toString("yyyy/MM/dd hh:mm"));
		qobject.insert("filetype", FileTypereturn(info));
				//2.插入文件图标：
					//要是发送图标数据，由于图片是二进制的数据，用文本的形式发送可能会丢失数据，要是再用二进制形式发送接收未免太麻烦了，用到的是将二进制数据转换成Base64编码，再发送：
						//2.1获取文件的图标
		auto icon = m_fileIconprovider.icon(info);			
		if (!icon.isNull())
		{
						//2.2将图标转换为16x16像素大小的QPixmap对象,将QPixmap对象转换为QImage对象
			auto img = icon.pixmap(16).toImage();		
						//2.3创建QByteArray类对象和QBuffer类对象 用于保存图像数据：
			QByteArray bytes;
			QBuffer buf(&bytes);
				/*
					QBuffer是Qt中的一个类，它提供了一个缓冲区，可以在内存中读写数据。它通常用于将数据保存到内存中，或者从内存中读取数据; 
					这里QBuffer对象buf被用来保存图像数据；
				*/
						//2.4将QImage保存为ICO格式的图像数据
			img.save(&buf, "ico");				
						//2.5关闭缓冲区：
			buf.close();
						//2.6插入图标数据的键值对：
			qobject.insert("icondata", QString::fromLatin1(bytes.toBase64())	/*将ICO格式的图像数据由拉丁编码转换为Base64编码的字符串*/	);
			//由什么样的编码转换成Base16编码，接收图像数据的时候就再转成什么样的编码
		}


		//将文件信息的JSON对象添加到文件数组中:
		fileArray.append(qobject);
	}

	//创建一个新的JSON对象来存储文件列表信息:
	QJsonObject jobject;
	jobject.insert("type",RESPONSE_FILE_LIST);
	jobject.insert("data", fileArray);
	jobject.insert("path", path);

	// 返回包含文件列表信息的JSON对象:
	return jobject;
}
void RemoteFileDialog::SendJson(const QJsonObject& qobject)
{
	m_websockclient->sendTextMessage(
		QJsonDocument(qobject).toJson(QJsonDocument::Compact)
		/*创建一个QJsonDocument对象，将QJsonObject对象转换为JSON文档，然后使用toJson(QJsonDocument::Compact)将其转换为紧凑格式的JSON字符串*/
	);
}
void RemoteFileDialog::GetRemoteFile()
{
	qDebug() << "m_remoteFileDir的规范路径（首次会为空）  > " << m_remoteFileDir.canonicalPath();


	if (!m_websockclient	/*如果客户端没有被创建*/ || !m_websockclient->isValid()	/*如果web客户端不可读不可写*/)
		return;


	//使用json类来解析和传输数据：
#if 0
	QJsonObject qobject;									//创建一个空的QJsonObject对象，用于存储JSON键值对
	qobject.insert("type", REQUEST_FILE_LIST);
	qobject.insert("path", m_remoteFileDir.canonicalPath()	/*m_remoteFileDir的规范路径*/);
	SendJson(qobject);
#else				//等效			下面的更简洁		但是更难理解
	SendJson(
		{
				{"type",REQUEST_FILE_LIST},					//类型是		请求远程对方文件返回列表		即发送请求
				{"path",m_remoteFileDir.canonicalPath()}	//每次进入和回退远程文件的目录，都要发送 请求远程再次回应 操作后的目录，所以要把此时的操作过后的远程文件目录也发过去
		}
	);
#endif
}
//用于获取数据
void RemoteFileDialog::UpdateRemoteFile(const QJsonObject& object)
{
	//解析QJsonArray中键为"path"的值，数据转换成字符串：
	auto path = object.value("path").toString();


	m_remoteFileModel->clear();


	//如果是首次设置下拉框的数据：
	if (-1 == ui->remoteFile_curfilepathCmb->currentIndex())
	{
		ui->remoteFile_curfilepathCmb->lineEdit()->setText(path);
		m_remoteFileDir.setPath(path);
	}
	//下拉框的保存路径不能大于10：
	if (ui->remoteFile_curfilepathCmb->count() > 10)
	{
		ui->remoteFile_curfilepathCmb->removeItem(0);
	}


	//解析QJsonArray中键为"data"的的值，数据转换成数组：
	QJsonArray jarray = object.value("data").toArray();
	//遍历这个数组，逐个插入到TableView视图中：
	for (int i = 0; i < jarray.size(); i++)
	{
		//获取jarray数组中的第i个元素，然后通将这个元素转换为QJsonObject对象。转换后的QJsonObject对象jfile可以用于访问和操作JSON对象中的数据:
		auto jfile = jarray.at(i).toObject();
		//通过object里面的键"filetype"来获取对应的值，所谓文件类型:
		auto filetype = jfile.value("filetype").toString();

		//给TableView要插入的数据信息进行加载：
		QList<QStandardItem* > items;
			//1.1添加首项：文件名和文件图标：
		auto item = new QStandardItem(jfile.value("filename").toString()/*通过object里面的键"filename"来获取对应的值，所谓文件名*/);
					//1.2加载图标：
		QImage img;
		img.loadFromData(QByteArray::fromBase64(jfile.value("icondata").toString().toLatin1()/*通过object里面的键"icondata"来获取对应的值，所谓图片数据*/),/*由Base64编码格式转换为拉丁编码*/
					"ico"				//设置图片输出格式为ico
						);
		item->setIcon(QPixmap::fromImage(img));												//设置当前文件名的图标；
		items.append(item);
			//2.添加其他项：文件大小，文件最后修改时间，文件类型：
		items.append(new QStandardItem(filetype == "文件夹" ? "" : FitByteDisplayText(jfile.value("filesize").toInteger())/*通过object里面的键"filesize"来获取对应的值，所谓文件大小*/	));				//加入该文件的大小
		items.append(new QStandardItem(jfile.value("filetime").toString()/*通过object里面的键"filetime"来获取对应的值，所谓文件最后修改时间*/));							//加入该文件的最后修改日期
		items.append(new QStandardItem(filetype));								//加入该文件的文件类型
		

		//给TableView插入数据信息：
		m_remoteFileModel->appendRow(items);


		/*
		注意：以下是对QTableView的视图水平表头和各列大小的的调整：
		*/
		// 获取水平表头
		QHeaderView* header = ui->remoteView->horizontalHeader();
		SetViewHorizontalHead(header,m_remoteFileModel,ui->remoteView);
	}
}
void RemoteFileDialog::setRemoteFilePath(const QString& path)
{
	m_remoteFileDir.setPath(path);
	GetRemoteFile();
}
void RemoteFileDialog::onRemoteFileBack()
{
	qDebug() << "back > ";
	m_remoteFileDir.cdUp();
	GetRemoteFile();
}
void RemoteFileDialog::onRemoteFileFlush()
{
	GetRemoteFile();
}
void RemoteFileDialog::onRemoteTableViewDoubleClicked(const QModelIndex& index)
{
	//搞出当前双击下标索引的文件的文件名：
	auto filename = m_remoteFileModel->data(m_remoteFileModel->index(index.row(), 0)).toString();
	//获取文件类型：
	auto filetype = m_remoteFileModel->data(m_remoteFileModel->index(index.row(), 3)).toString();
	
	if (filetype == "文件夹")				//如果是个文件夹，就进入，并且更新模型视图
	{
		m_remoteFileDir.cd(filename);
		GetRemoteFile();
	}
}







//用来识别文件类型的函数：
static QString FileTypereturn(const QFileInfo& info)
{
	if (info.isAlias()) { return "别名"; }      //mac
	if (info.isBundle()) { return "bundle"; }     //mac
	if (info.isDir()) { return "文件夹"; }
	if (info.isExecutable()) { return "exe"; }
	if (info.isFile()) { return info.suffix(); }
	if (info.isHidden()) { return "隐藏文件"; }
	if (info.isJunction()) { return "lnk"; }
	if (info.isShortcut()) { return "lnk"; }
	if (info.isSymLink()) { return "lnk"; }
	if (info.isSymbolicLink()) { return "lnk"; }
	return "unknown";
}







//传输展示视图：
void RemoteFileDialog::detailinit()
{
	m_detailModel = new QStandardItemModel(this);
	ui->detailView->setModel(m_detailModel);

	ui->detailView->setEditTriggers(QTableView::NoEditTriggers);									//设置不可选取
	ui->detailView->setSelectionMode(QTableView::SelectionMode::ContiguousSelection);				//设置选择模式
	ui->detailView->setSelectionBehavior(QTableView::SelectionBehavior::SelectRows);				//设置一行选取
	ui->detailView->verticalHeader()->setVisible(false);											//设置左边序列号取消显示
	ui->detailView->setShowGrid(false);														//设置在QTableView中隐藏列之间的分隔线

	//更新TableView视图数据信息：
	UpdateDetailView();

	QObject::connect(ui->transmitBtn, &QPushButton::clicked, this, [=]
		{
			m_detailModel->clear();
		});
	QObject::connect(ui->allstartBtn, &QPushButton::released, this, &RemoteFileDialog::onAllStart);
	QObject::connect(ui->allpauseBtn, &QPushButton::released, this, &RemoteFileDialog::onAllPause);
	QObject::connect(ui->allcancelBtn, &QPushButton::released, this, &RemoteFileDialog::onAllCancel);


}
void RemoteFileDialog::UpdateDetailView(QString data)
{
	qDebug() << "transmitdata >" << data;


	QStandardItem* item = new QStandardItem(data);
	m_detailModel->appendRow(item);

	/*
	注意：以下是对QTableView的视图水平表头和各列大小的的调整：
	*/
	// 获取水平表头:
	QHeaderView* header = ui->detailView->horizontalHeader();
	SetViewHorizontalHead(header, m_detailModel, ui->detailView);


	//3.TableView视图	跳转到最下面，因为没有更新视图，所以新创建的文件夹默认是在该视图的最后的，所以要跳转到最下面，方便修改文件名：
	ui->detailView->scrollToBottom();
}
void RemoteFileDialog::onAllStart()
{
	emit totalsleep(0);
}
void RemoteFileDialog::onAllPause()
{
	emit totalsleep(1);
}
void RemoteFileDialog::onAllCancel()
{
	emit totalsleep(2);
}





//右上三个功能按钮：
void RemoteFileDialog::on_minBtn_released()
{
	qDebug() << "on_minBtn_released released\n";
	this->showMinimized();
}
void RemoteFileDialog::on_maxBtn_released()
{
	qDebug() << "on_minBtn_released released\n";
	if (this->isMaximized())			//如果此时是最大化，那就回复原来大小
	{
		this->showNormal();
	}
	else                               //如果不是，才最大化窗口 
	{
		this->showMaximized();
	}

}
void RemoteFileDialog::on_closeBtn_released()
{
	qDebug() << "on_minBtn_released released\n";
	this->close();
}


//设置窗口背景：
void RemoteFileDialog::paintEvent(QPaintEvent* ev)
{

}
